// vbclient.cpp
#define _WIN32_DCOM
#include <olectl.h>
#include <conio.h>
#include <iostream.h>
#include <stdio.h>
#include "Component\component.h"

// {8788DE0C-1441-11D3-8EF5-00C04F68F506}
const IID IID_EventClass = {0x8788DE0C, 0x1441, 0x11D3, {0x8E, 0xF5, 0x00,
0xC0, 0x4F, 0x68, 0xF5, 0x06}};

// {8788DE0B-1441-11D3-8EF5-00C04F68F506}
const CLSID CLSID_InsideCOM = {0x8788DE0B, 0x1441, 0x11D3, {0x8E, 0xF5, 0x00, 
    0xC0, 0x4F, 0x68, 0xF5, 0x06}};

class CSink : public IUnknown
{
public:
	// IUnknown
	ULONG __stdcall AddRef();
	ULONG __stdcall Release();
	HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);

	// IDispatch
	HRESULT __stdcall GetTypeInfoCount(UINT* pCountTypeInfo);
	HRESULT __stdcall GetTypeInfo(UINT iTypeInfo, LCID lcid, ITypeInfo** ppITypeInfo);
	HRESULT __stdcall GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId);
	HRESULT __stdcall Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr);

    HRESULT virtual __stdcall Message(short* KeyAscii);

	CSink() : m_cRef(0) { }
	~CSink() { }

private:
	long m_cRef;
};

HRESULT CSink::Message(short* KeyAscii)
{
	cout << "Message" << endl;
	return S_OK;
}

HRESULT CSink::GetTypeInfoCount(UINT* pCountTypeInfo)
{
	cout << "GetTypeInfoCount" << endl;
	*pCountTypeInfo = 0;
	return S_OK;
}

HRESULT CSink::GetTypeInfo(UINT iTypeInfo, LCID lcid, ITypeInfo** ppITypeInfo)
{
	cout << "GetTypeInfo" << endl;
	return S_OK;
}

HRESULT CSink::GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId)
{
	cout << "GetIDsOfNames" << endl;
	if(riid != IID_NULL)
		return DISP_E_UNKNOWNINTERFACE;
	return S_OK;
}

HRESULT CSink::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
{
	cout << "Invoke" << endl;
	if(riid != IID_NULL)
		return DISP_E_UNKNOWNINTERFACE;
	return S_OK; 
}

ULONG CSink::AddRef()
{
	cout << "AddRef" << endl;
	return ++m_cRef;
}

ULONG CSink::Release()
{
	cout << "Release" << endl;
	if(--m_cRef != 0)
		return m_cRef;
	delete this;
	return 0;
}

HRESULT CSink::QueryInterface(REFIID riid, void** ppv)
{
	if(riid == IID_IUnknown)
	{
		cout << "Client: CSink::QueryInterface() for IID_IUnknown" << endl;
		*ppv = (IUnknown*)this;
	}
	else if(riid == IID_IDispatch)
	{
		cout << "Client: CSink::QueryInterface() for IID_IDispatch" << endl;
		*ppv = (IDispatch*)this;
	}
	else if(riid == IID_EventClass)
	{
		cout << "Client: CSink::QueryInterface() for IID_EventClass" << endl;
		*ppv = (IDispatch*)this;
	}
	else 
	{
		*ppv = NULL;
		return E_NOINTERFACE;
	}
	AddRef();
	return S_OK;
}

/*HRESULT CSink::GotMessage(int Message)
{
	if(Message == (int)'b' || Message == (int)'B')
		PlaySound("BrockschmidtQuack", NULL, SND_RESOURCE|SND_ASYNC);
	cout << "CSink::GotMessage is " << (char)Message << endl;
	return S_OK;
}*/

void main()
{
	cout << "Client: Calling CoInitialize()" << endl;
	CoInitializeEx(NULL, COINIT_MULTITHREADED);
	
	IUnknown* pUnknown;
	cout << "Client: Calling CoCreateInstance()" << endl;
	CoCreateInstance(CLSID_InsideCOM, NULL, CLSCTX_LOCAL_SERVER, IID_IUnknown, (void**)&pUnknown);

//	ISum* pSum;
//	cout << "Client: Calling QueryInterface() for ISum on " << pUnknown << endl;
//	HRESULT hr = pUnknown->QueryInterface(IID_ISum, (void**)&pSum);
//	if(FAILED(hr))
//		cout << "QueryInterface FAILED" << endl;

//	int sum;
//	pSum->Sum(17, 2, &sum);
//	cout << "pSum->Sum(17, 2) = " << sum << endl;

	IConnectionPointContainer* pConnectionPointContainer;
	HRESULT hr = pUnknown->QueryInterface(IID_IConnectionPointContainer, (void**)&pConnectionPointContainer);
	if(SUCCEEDED(hr))
	{
		IConnectionPoint* pConnectionPoint;
		hr = pConnectionPointContainer->FindConnectionPoint(IID_EventClass, &pConnectionPoint);
		cout << "FindConnectionPoint returns " << hr << " pConnectionPoint = " << pConnectionPoint << endl;
		printf("FindConnectionPoint = %0x\n", hr);

		CSink* mySink = new CSink;
		DWORD dwCookie;
		pConnectionPoint->Advise((IUnknown*)mySink, &dwCookie);

		cout << "Press any key to exit" << endl;
		_getch();

		pConnectionPoint->Unadvise(dwCookie);
		pConnectionPoint->Release();
		pConnectionPointContainer->Release();
	}

//	cout << "Client: Calling Release() for pSum" << endl;
//	hr = pSum->Release();

	cout << "Client: Calling Release() for pUnknown" << endl;
	hr = pUnknown->Release();

	cout << "Client: Calling CoUninitialize()" << endl;
	CoUninitialize();
}